/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.engine.repository.adaptor;

import com.inspur.edp.bef.api.BefRtBeanUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.engine.core.be.EngineBEManager;
import com.inspur.edp.bef.engine.entity.BeModelResInfo;
import com.inspur.edp.bef.engine.entity.EngineChildData;
import com.inspur.edp.bef.engine.entity.EngineRootData;
import com.inspur.edp.bef.engine.repository.typetransprocesser.EnumEngineIntProcesser;
import com.inspur.edp.bef.engine.repository.typetransprocesser.EnumEngineVarcharProcesser;
import com.inspur.edp.bef.engine.repository.typetransprocesser.VarcharIntTransProcesser;
import com.inspur.edp.bef.engine.repository.util.ReadUtils;
import com.inspur.edp.cef.api.repository.GspDbDataType;
import com.inspur.edp.cef.api.repository.IRootRepository;
import com.inspur.edp.cef.api.repository.ITypeTransProcesser;
import com.inspur.edp.cef.api.repository.readerWriter.ICefReader;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.*;
import com.inspur.edp.cef.designtime.api.entity.GspCommonField;
import com.inspur.edp.cef.entity.condition.FilterCondition;
import com.inspur.edp.cef.entity.condition.SortCondition;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.repository.adaptor.EntityRelationalAdaptor;
import com.inspur.edp.cef.repository.adaptor.KeyWordsManager;
import com.inspur.edp.cef.repository.assembler.LogicDeleteInfo;
import com.inspur.edp.cef.repository.dac.EntityDac;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfo;
import com.inspur.edp.cef.repository.exception.CefRepositoryException;
import com.inspur.edp.cef.repository.sqlgenerator.BaseSqlGenerator;
import com.inspur.edp.cef.repository.typetransprocesser.*;
import com.inspur.edp.cef.repository.utils.StringUtil;
import com.inspur.edp.cef.repository.utils.TenantUtil;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.commonmodel.engine.api.common.CMEngineUtil;
import com.inspur.edp.commonmodel.engine.api.data.AssociationInfo;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.dataaccess.DbType;
import io.iec.edp.caf.databaseobject.api.entity.DataType;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectColumn;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectTableCore;
import java.util.ArrayList;
import java.util.HashMap;
import lombok.var;
import org.springframework.util.StringUtils;

public abstract class BefBaseAdaptor extends EntityRelationalAdaptor {

    private GspBizEntityObject bizEntityObject;
    private HashMap<String, Integer> propIndexMappingDict;
    private String tableAlias;
    private String deleteSql;
    private String modifySql;
    private String retrieveBatchSql;
    private String retrieveSql;
    private String insertSql;
    private boolean isChildAdaptor;
    private BaseSqlGenerator sqlGenerator;
    //    private DatabaseObjectTable dbo;
    private DatabaseObjectTableCore dbo;
    private EntityDac entityDac;
    private IGspCommonElement parentIdEle;

    protected abstract BaseSqlGenerator getSqlGenerator();
    public BefBaseAdaptor(GspBizEntityObject bizEntityObject)
    {
        this(bizEntityObject,null);
    }

    public BefBaseAdaptor(GspBizEntityObject bizEntityObject, EntityDac entityDac) {
        super(false);
        this.bizEntityObject = bizEntityObject;
        dbo = (DatabaseObjectTableCore) BefRtBeanUtil.getDboRtService().getDatabaseObject(bizEntityObject.getRefObjectName());
        this.entityDac = entityDac;
        if (dbo == null) {
            String mesg = String
                    .format("模型[%s]上的节点[%s]对应的dbo没有获取到，请检查dbo是否成功部署到正确的数据库中，dboId为：%s",
                            bizEntityObject.getBelongModel().getName(), bizEntityObject.getName(),
                            bizEntityObject.getRefObjectName());
            throw new CefRepositoryException(mesg);
        }
        isChildAdaptor = bizEntityObject.getParentObject() != null;
        tableAlias = getWrappedAlias(bizEntityObject.getCode());
        if (isChildAdaptor) {
            String parentIdEleId = bizEntityObject.getKeys().get(0).getSourceElement();
            parentIdEle = bizEntityObject.findElement(parentIdEleId);
        }
        initAssociations();
        initColumns();
        sqlGenerator = getSqlGenerator();
    }

    //兼容处理IDP年度表
    private String getWrappedAlias(String alias){
        alias = alias.trim();
        alias = alias.replace("$", "");
        return alias;
    }

    public CefEntityResInfoImpl getEntityResInfo() {
        //变量缓存?
        return (CefEntityResInfoImpl) EngineBEManager.getCefModelResourceInfo(bizEntityObject.getBelongModel()).getCustomResource(bizEntityObject.getCode());
    }

    @Override
    public LogicDeleteInfo getLogicDeleteInfo(){
        LogicDeleteInfo logicDeleteInfo = new LogicDeleteInfo(false, "IsDelete");
        if(this.bizEntityObject.getLogicDeleteControlInfo() != null && this.bizEntityObject.getLogicDeleteControlInfo().getEnableLogicDelete()){
            logicDeleteInfo.setEnableLogicDelete(true);
            for(IGspCommonField gspCommonField: bizEntityObject.getContainElements()){
                if(gspCommonField.getID().equals(bizEntityObject.getLogicDeleteControlInfo().getLogicDeleteControlElementId()))
                {
                    logicDeleteInfo.setLabelId(gspCommonField.getLabelID());
                    break;
                }
            }
        }
        return logicDeleteInfo;
    }

    @Override
    protected String getDboID() {
        return bizEntityObject.getRefObjectName();
    }

    //region PropertyColumn
    @Override
    protected boolean hasPropColumnMappping() {
        return propIndexMappingDict != null;
    }

    @Override
    protected HashMap<String, Integer> getPropertyColumnMapping() {
        return propIndexMappingDict;
    }

    @Override
    protected void setPropertyColumnMapping(HashMap<String, Integer> mappingDict) {
        propIndexMappingDict = mappingDict;
    }
    //endregion

    //region InitColumns
    @Override
    protected void initColumns() {
        for (var element : bizEntityObject.getContainElements()) {
            if (element.getObjectType() == GspElementObjectType.DynamicProp) {
                continue;
            }
            if(element.getIsVirtual()){
                initColumn((IGspCommonElement) element, (IGspCommonElement) element, null);
                continue;
            }
            if (element.getIsUdt()) {
                initUdtColumn((IGspCommonElement) element);
            } else {
                var column = dbo.getColumnById(((IGspCommonElement) element).getColumnID());
                if (column == null) {
                    throw new CefRepositoryException(
                            "通过io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectTableCore.getColumnById()方法在code为["
                                    + dbo.getCode() + "]的dbo中找不到columnid为[" + ((IGspCommonElement) element)
                                    .getColumnID() + "]的dbo列, BE字段编号为[" + element.getCode() + "]BE元数据ID编号分别为["
                                    + this.bizEntityObject.getBelongModel().getId()+"][" + this.bizEntityObject.getBelongModel().getCode()
                                    + "],请检查BE元数据和DBO是否均已正确部署,BE元数据部署后保存在gspmdrtcontent或gspmdcustomcontent表中,DBO部署后保存在gspdatabaseobject表中. ");
                }
                initColumn((IGspCommonElement) element, (IGspCommonElement) element, column);
            }
        }
    }

    private void initUdtColumn(IGspCommonElement element) {
        if (element.getChildElements().size() == 1) {
            var column = dbo.getColumnById(element.getColumnID());
            if (column == null) {
                throw new CefRepositoryException("dbo["+dbo.getCode()+"]中找不到字段[" + element.getLabelID() + "]对应的列,columnid:" + element.getColumnID());
            }
            initColumn(element, element, column);

            return;
        }

        UnifiedDataTypeDef unifiedDataTypeDef= null;

        for (var childElement : element.getChildElements()) {

            var childEle =
                    (IGspCommonElement) ((childElement instanceof IGspCommonElement) ? childElement : null);

            var column = dbo.getColumnById(childEle.getColumnID());
            if (column == null) {
                throw new CefRepositoryException("dbo中找不到" + childEle.getLabelID() + "对应的列");
            }
            if(unifiedDataTypeDef==null)
                unifiedDataTypeDef=(UnifiedDataTypeDef) CMEngineUtil.getMetadata(element.getUdtID()).getContent();
            ComplexDataTypeDef complexDataTypeDef= (ComplexDataTypeDef) unifiedDataTypeDef;
            String refedUdtElementID = element.getMappingRelation().getMappingInfo(childEle.getID());
            IGspCommonField refedElement =  complexDataTypeDef.findElement(refedUdtElementID);
            if(childEle.getObjectType()!=refedElement.getObjectType())
            {
                childEle.setObjectType(refedElement.getObjectType());
                childEle.setEnumIndexType(refedElement.getEnumIndexType());
                childEle.setContainEnumValues(refedElement.getContainEnumValues());
            }
            // TODO 暂时没法只根据element判断是否是ChildElement
            childEle.setIsUdt(true);

            initColumn(childEle, element, column);
        }

    }

    private void initColumn(IGspCommonElement element, IGspCommonElement belongElement, DatabaseObjectColumn dboColumn) {
        GspDbDataType dataType =  GspDbDataType.VarChar;
        DbColumnInfo dbColumnInfo = new DbColumnInfo();
        dbColumnInfo.setColumnName(element.getLabelID());
        boolean isAssociateRefElement = false;
        //init方法的都是基础字段
        if(element.getIsVirtual()){
            dbColumnInfo.setDbColumnName("");
            dbColumnInfo.setVirtual(true);
            dataType = getVirtualDbType(element);
        }
        else {
            dataType = transDataType(dboColumn.getDataType());
            dbColumnInfo.setDbColumnName(isAssociateRefElement ? "" : dboColumn.getCode());
        }

        dbColumnInfo.setColumnType(dataType);
        dbColumnInfo.setLength(element.getLength());
        dbColumnInfo.setPrecision(element.getPrecision());
        dbColumnInfo.setDefaultValue(null);
        dbColumnInfo.setIsPrimaryKey(isPrimaryKey(element));
        dbColumnInfo.setIsAssociateRefElement(isAssociateRefElement);
        dbColumnInfo.setIsMultiLang(element.getIsMultiLanguage());
        dbColumnInfo.setIsParentId(isParentColumn(element));
        dbColumnInfo.setIsUdtElement(element.getIsUdt());
        dbColumnInfo.setIsAssociation(element.getObjectType() == GspElementObjectType.Association);
        dbColumnInfo.setIsEnum(element.getObjectType() == GspElementObjectType.Enum);
        dbColumnInfo.setBelongElementLabel(belongElement == null ? "" : belongElement.getLabelID());
        dbColumnInfo.setTypeTransProcesser(getTypeProcesser(dataType, element, (dboColumn == null) ? 0 : dboColumn.getLength()));
        if(element instanceof GspCommonField){
            GspCommonField gspCommonField = (GspCommonField) element;
            if(gspCommonField.getSelectFieldRepoConfig() != null && !com.inspur.edp.cef.spi.jsonser.base.StringUtils.isNullOrEmpty(gspCommonField.getSelectFieldRepoConfig().getConfigClassImpl())){
                dbColumnInfo.setFieldReposExtendConfigId(gspCommonField.getSelectFieldRepoConfig().getConfigId());
            }
        }

        super.getContainColumns().add(dbColumnInfo);
    }

    private GspDbDataType getVirtualDbType(IGspCommonElement element){
        GspDbDataType dbDataType = GspDbDataType.VarChar;
        switch (element.getMDataType()){
            case String:
                dbDataType = GspDbDataType.VarChar;
                break;
            case Integer:
                dbDataType = GspDbDataType.Int;
                break;
            case Decimal:
                dbDataType = GspDbDataType.Decimal;
                break;
            case Boolean:
                dbDataType = GspDbDataType.Char;
                break;
            case Date:
                dbDataType = GspDbDataType.Date;
                break;
            case DateTime:
                dbDataType = GspDbDataType.DateTime;
                break;
            case Text:
                dbDataType = GspDbDataType.Clob;
                break;
            case Binary:
                dbDataType = GspDbDataType.Blob;
                break;
        }
        return dbDataType;
    }

    private GspDbDataType transDataType(DataType dataType) {
        GspDbDataType dbDataType = GspDbDataType.VarChar;
        switch (dataType) {
            case Char:
                dbDataType = GspDbDataType.Char;
                break;
            case Varchar:
                dbDataType = GspDbDataType.VarChar;
                break;
            case Blob:
                dbDataType = GspDbDataType.Blob;
                break;
            case DateTime:{
                //慢慢的都改过来。
                if(CAFContext.current.getDbType() == DbType.OceanBase){
                    dbDataType = GspDbDataType.Date;
                }
                else {
                    dbDataType = GspDbDataType.DateTime;
                }
                break;
            }
            case TimeStamp:
                dbDataType = GspDbDataType.DateTime;
                break;
            case Clob:
                dbDataType = GspDbDataType.Clob;
                break;
            case Int:
            case LongInt:
                dbDataType = GspDbDataType.Int;
                break;
            case Decimal:
            case Float:
                dbDataType = GspDbDataType.Decimal;
                break;
            case NChar:
                dbDataType = GspDbDataType.NChar;
                break;
            case NVarchar:
                dbDataType = GspDbDataType.NVarChar;
                break;
            case NClob:
                dbDataType = GspDbDataType.NClob;
                break;
            case Boolean:
                dbDataType = GspDbDataType.Boolean;
                break;
            case Jsonb:
                dbDataType = GspDbDataType.Jsonb;
                break;
        }
        return dbDataType;
    }

    private ITypeTransProcesser getTypeProcesser(
            GspDbDataType dbType, IGspCommonElement element,int length) {
        if (element.getObjectType() == GspElementObjectType.Enum) {
            switch (dbType) {
                case Int:
                    return new EnumEngineIntProcesser((GspBizEntityElement) element);
                case VarChar:
                case NVarChar:
                    return new EnumEngineVarcharProcesser((GspBizEntityElement) element);
            }
        }
//        if(element.getObjectType() ==GspElementObjectType.Enum){
//            return VarcharTransProcesser.getInstacne();
//        }
        switch (element.getMDataType()) {
            case Boolean:
                if (dbType == GspDbDataType.Int) {
                    return Bool2IntProcesser.getInstacne();
                }
                if (dbType == GspDbDataType.Char||dbType==GspDbDataType.VarChar) {
                    return Bool2CharProcesser.getInstacne();
                }
                if(dbType==GspDbDataType.Boolean)
                    return BoolTransProcesser.getInstacne();
                break;
            case Date:
                if((dbType==GspDbDataType.Char||dbType==GspDbDataType.VarChar)&&length==8)
                    return DateTime2Char8Processer.getInstacne();
                return DateTimeTransProcesser.getInstacne();
            case DateTime:
                return DateTimeTransProcesser.getInstacne();
            case Decimal:
                if (dbType == GspDbDataType.Decimal) {
                    return DecimalTransProcesser.getInstacne();
                }
                break;
            case Integer:
                if (dbType == GspDbDataType.Int) {
                    return IntTransProcesser.getInstacne();
                }
                break;
            case String:
                if(dbType==GspDbDataType.Int){
                    return VarcharIntTransProcesser.getInstacne();
                }
                return VarcharTransProcesser.getInstacne();
            case Text:
                return ClobTransProcesser.getInstacne();
            case Binary:
                return BinaryTransProcesser.getInstacne();
        }

        throw new CefRepositoryException(
                "#GSPBefError#"
                        + "没有找到字段类型为"
                        + element.getMDataType().toString()
                        + "，数据库类型为"
                        + dbType.toString()
                        + "的转换器，字段标签："+element.getLabelID()+",字段名称："+element.getName()+", 所属be："+element.getBelongObject().getBelongModel().getCode()
                        + "#GSPBefError#");
    }

    private boolean isPrimaryKey(IGspCommonElement element) {
        return bizEntityObject.getIDElement().getID().equals(element.getID());
    }

    private boolean isParentColumn(IGspCommonElement element) {
        if (isChildAdaptor) {
            return parentIdEle.getID().equals(element.getID());
        }
        return false;
    }
    // endregion

    //region Filter & Sort
    @Override
    protected ArrayList<FilterCondition> getDefaultFilterCondition() {
        return null;
    }

    @Override
    protected ArrayList<SortCondition> getDefaultSortCondition() {
        return null;
    }

    //endregion

    @Override
    public String getPrimaryKey() {
        return dbo.getColumnById(bizEntityObject.getIDElement().getColumnID()).getCode();
    }

    @Override
    public String getTableAlias() {
        return tableAlias;
    }

    @Override
    public void setTableAlias(String value) {
        tableAlias = value;
    }

    @Override
    protected String getConfigId() {
        return bizEntityObject.getBelongModel().getGeneratedConfigID();
    }

    //region Delete
    @Override
    protected String innerGetDeleteSql() {
        return getDeleteSqlStr();
    }

    @Override
    protected String getDeleteSqlBatch() {
        return getDeleteSqlStr();
    }

    private String getDeleteSqlStr() {
        if (deleteSql == null)
            deleteSql = String.format(sqlGenerator.getDeleteSql(), "@TableName@", tableAlias);
        return deleteSql;
    }

    //endregion

    // region Insert
    @Override
    protected String innerGetInsertSql() {
        batchInsert = true;
        if (insertSql == null)
            initInsertSql();
        return insertSql;
    }

    private void initInsertSql() {
        String sql = sqlGenerator.getInsertSql();
        buildInsertColumnsAndParams();
        insertSql = String.format(sql, "@TableName@", insertColumns, insertParams);
    }

    private String insertColumns;
    private String insertParams;

    private void buildInsertColumnsAndParams() {
        //跟之前一致，并且在当前实例上做缓存。
        StringBuilder columnNames = new StringBuilder();
        StringBuilder valueParamter = new StringBuilder();
        for (DbColumnInfo columnInfo : getContainColumns()) {
            if (columnInfo.getIsAssociateRefElement()) {
                continue;
            }
            if(columnInfo.isVirtual()){
                continue;
            }
            if (columnNames.toString() != null && "".equals(columnNames.toString()) == false) {
                columnNames.append(", ");
                valueParamter.append(", ");
            }
            if (columnInfo.getIsMultiLang()) {
                columnNames.append(KeyWordsManager.getColumnAlias(getMultiLangColumnName(columnInfo.getDbColumnName())));
            } else {
                columnNames.append(KeyWordsManager.getColumnAlias(columnInfo.getDbColumnName()));
            }
            valueParamter.append("?");
        }

        if (TenantUtil.IsDiscriminator()) {
            String tenantColName = TenantUtil.GetTenantColumnName();
            columnNames.append(", ").append(tenantColName);
            valueParamter.append(", ").append("?");
        }

        insertColumns = columnNames.toString();
        insertParams = valueParamter.toString();
    }

    protected String getMultiLangColumnName(String columnName) {
        //string currentLanguage = I18NUtils.getCurrentLanguage();
        //return columnName + I18NUtils.getFieldSuffix(currentLanguage);
        return columnName + "@Language@";
    }

    //endregion

    //region Modify
    @Override
    protected String innerGetModifySql() {
        if (modifySql == null) {
            modifySql = String.format("Update %1$s Set", "@TableName@");
        }
        return modifySql;
    }

    //endregion

    @Override
    protected Object getPropertyChangeValue(String propertyName, Object propertyValue) {
        for (var element : bizEntityObject.getContainElements()) {
            if(element.getIsUdt()){
                if(!element.getLabelID().equals(propertyName) && !containChildElementByLabelId(element, propertyName))
                    continue;
                return ReadUtils.getUdtValue(bizEntityObject,propertyName,element.getLabelID(),propertyValue);
            }
            if (!element.getLabelID().equals(propertyName))
                continue;
            if (element.getObjectType() == GspElementObjectType.Association)
                return ((AssociationInfo) propertyValue).getValue(element.getLabelID());
//            if (element.getObjectType() == GspElementObjectType.Enum)
//                return getEnumKey(element, (String) propertyValue);
            if(element.getMDataType()==GspElementDataType.Date)
                return  this.getContainColumns().getItem(element.getLabelID()).
                        getTypeTransProcesser().transType(propertyValue);
            return propertyValue;
        }
        throw new CefRepositoryException("未找到字段" + propertyName);
    }

    private Object getEnumKey(IGspCommonField element, String code) {
        for (GspEnumValue enumValue : element.getContainEnumValues()) {
            if (!enumValue.getValue().equals(code))
                continue;
            if (element.getEnumIndexType() == EnumIndexType.String)
                return enumValue.getStringIndex();
            return enumValue.getIndex();
        }
        throw new CefRepositoryException("字段" + element.getLabelID()
                + "中没有索引编号为" + code + "的枚举项");
    }

    //region GetData
    @Override
    protected String getGetDataByIdsSql() {
        if (retrieveBatchSql == null) {
            retrieveBatchSql = String.format(sqlGenerator.getRetrieveBatchSql(), "%1$s", "%2$s", tableAlias + "." + getContainColumns().getPrimaryKey().getDbColumnName(), "%3$s");
        }

        return retrieveBatchSql;
    }

    @Override
    protected String getGetDataByIdSql() {

        if (retrieveSql == null) {
            retrieveSql = String.format(
                    sqlGenerator.getRetrieveSql(),
                    "%1$s",
                    "%2$s",
                    tableAlias + "." + getContainColumns().getPrimaryKey().getDbColumnName(),
                    "%3$s");
        }
        return retrieveSql;
    }

    private String versionPropName;
    @Override
    protected String getVersionControlPropName() {
        if(!bizEntityObject.getIsRootNode()){
            return "";
        }
        if (versionPropName == null) {
            String versionElementId = bizEntityObject.getBelongModel().getVersionContronInfo().getVersionControlElementId();
            if (StringUtils.isEmpty(versionElementId)) {
                versionPropName = "";
            } else {
                IGspCommonElement versionElement = bizEntityObject.findElement(versionElementId);
                if (versionElement == null) {
                    throw new CefRepositoryException(
                            bizEntityObject.getBelongModel().getCode().concat("业务实体元数据结构错误,版本字段不存在:").concat(versionElementId));
                }
                versionPropName = versionElement.getLabelID();
            }
        }
        return versionPropName;
    }
    //endregion

    //region JoinTable
    @Override
    public String getParentJoin() {
        if (!isChildAdaptor)
            return null;
        return getJoinTable();
    }

    private String getJoinTable() {
//        String parenTableName = "@ParentTableName@  " + bizEntityObject.getParentObject().getCode(); // getParentTableName();//{3}
        String parentPrimaryKey = getParentTablePrimaryKey(); //{5}
        if (parentPrimaryKey.equals("") || parentPrimaryKey == null) {
            throw new CefRepositoryException("未找到父表主键字段，请检查配置");
        }
        String parentIdColumnName = getWrappedAlias(getTableAlias()) + "." + getParentIdColumnName();
        String parentAlias = bizEntityObject.getParentObject().getCode();
        parentAlias = parentAlias.trim();
        parentAlias = parentAlias.replace("$", "");
        String joinSql = sqlGenerator.getInnerJoinTableName().replace("@ParentTableAlias@",parentAlias)
                .replace("@ParentID@", parentIdColumnName)
                .replace("@PrimaryID@", parentPrimaryKey);
        return joinSql;
    }

    /**
     * 获取主表的关联字段
     * 默认子表记录主表的主键，IDP支持记录非主键字段，这里要支持一下
     * @return
     */
    private String getParentTablePrimaryKey() {
        IGspCommonElement parentElement = null;
        String parentElementId = bizEntityObject.getKeys().get(0).getTargetElement();
        parentElement = bizEntityObject.getParentObject().findElement(parentElementId);

        String alias = bizEntityObject.getParentObject().getCode();
        alias = alias.trim();
        alias = alias.replace("$", "");
        if(parentElement == null){
            parentElement = bizEntityObject.getParentObject().getIDElement();
            if (parentElement == null)
                throw new CefRepositoryException("对象" + alias + "中没有设置主键字段，请去元数据设计器中查看");
        }


        var parentDbo = (DatabaseObjectTableCore) BefRtBeanUtil.getDboRtService()
                .getDatabaseObject(bizEntityObject.getParentObject().getRefObjectName());


        var dbColumn = parentDbo.getColumnById(parentElement.getColumnID());
        if (dbColumn == null)
            throw new CefRepositoryException("DBO" + parentDbo.getCode() + "中没有找到Id为" + parentElement.getColumnID()
                    + "的字段，对应Be字段编号为" + parentElement.getCode());
        return alias + "." + dbColumn.getCode();
    }

    /**
     * 子表ParentID是否关联主表的主键字段
     * @return
     */
    public boolean isAssoParentPrimaryKey(){
        IGspCommonElement parentElement = null;
        if(bizEntityObject.getParentObject() == null)
            return false;
        String parentElementId = bizEntityObject.getKeys().get(0).getTargetElement();
        parentElement = bizEntityObject.getParentObject().findElement(parentElementId);

        IGspCommonElement idElement = bizEntityObject.getParentObject().getIDElement();
        if(parentElement != null && idElement != null && idElement.getID().equalsIgnoreCase(parentElement.getID())){
            return true;
        }
        return false;
    }

    private String getParentIdColumnName() {
        if (parentIdEle == null)
            throw new CefRepositoryException("对象" + bizEntityObject.getCode() + "中没有设置ParentId字段，请去元数据设计器中查看");
        var parentIdColumn = dbo.getColumnById(parentIdEle.getColumnID());
        if (parentIdColumn == null)
            throw new CefRepositoryException("DBO" + dbo.getCode() + "中没有找到Id为" + parentIdEle.getColumnID()
                    + "的字段，对应Be字段编号为" + parentIdEle.getCode());
        return parentIdColumn.getCode();
    }

    @Override
    protected String getJoinTableName() {
        return getSqlGenerator().getJoinTableName();
    }

    //endregion

    //region Value
    @Override
    public ICefData createInstance(ICefReader reader) {
        IEntityData data = null;
        if (isChildAdaptor)
            data = new EngineChildData(bizEntityObject, getResInfo(bizEntityObject.getCode()));
        else
            data = new EngineRootData(bizEntityObject, getResInfo(bizEntityObject.getCode()));
        for (var element : bizEntityObject.getContainElements()) {
            if (element.getIsUdt())
                ReadUtils.setUdtData(reader, false, data, (IGspCommonElement)element);
            else if (element.getObjectType()== GspElementObjectType.DynamicProp){
                continue;
            } else {
                var value = ReadUtils.getValue((IGspCommonElement) element, reader);
                data.setValue(element.getLabelID(), value);
            }
        }
        return data;
    }

    @Override
    public final EntityDac getEntityDac() {
        return entityDac;
    }

    private BeModelResInfo modelResInfo;
    private CefEntityResInfoImpl getResInfo(String nodeCode){
        if(modelResInfo == null) {
            modelResInfo = EngineBEManager.createResInfo(bizEntityObject.getBelongModel());
        }
        return (CefEntityResInfoImpl) modelResInfo.getCustomResource(nodeCode);
    }

    @Override
    public Object getPersistenceValue(String colName, ICefData data) {
        for (var element : bizEntityObject.getContainElements()) {

            //udt字段
            if(element.getIsUdt()){
                if(!element.getLabelID().equals(colName) && !containChildElementByLabelId(element, colName))
                    continue;
                var udtData = data.getValue(element.getLabelID());
                return ReadUtils.getUdtValue(bizEntityObject,colName,element.getLabelID(),udtData);
            }

            //非udt字段
            if (!element.getLabelID().equals(colName))
                continue;

            return this.getContainColumns().getItem(element.getLabelID()).
                    getTypeTransProcesser().transType(data.getValue(element.getLabelID()));

//            return UdtManagerUtils.getUdtRepositoryFactory().createRepository("com.inspur.gs.scm.sd.salesorder.udt.belongdepartment.BelongDepartment").getPersistenceValue("BelongDepartment", ((IZUser) data).getDpet());
        }

        throw new CefRepositoryException("没有找到字段" + colName);
    }

    private static boolean containChildElementByLabelId(IGspCommonField element, String lableId) {
        for (IGspCommonField childElement :
                element.getChildElements()) {
            if (childElement.getLabelID().equals(lableId))
                return true;
        }
        return false;
    }

    @Override
    public HashMap<String, String> getAssosPropDBMapping(String propName)//生成引用解析的时候 会用到。
    {
        for(IGspCommonField element : this.bizEntityObject.getContainElements()){
            if(!element.getLabelID().equalsIgnoreCase(propName))
                continue;
            //如果是多值多列UDT
            if (element.getIsUdt()){
                UnifiedDataTypeDef udt = CMEngineUtil.getMetadataContent(element.getUdtID());
                if (udt == null)
                    throw new CefRepositoryException("没有找到业务字段元数据：" + element.getUdtID());

                if (udt instanceof ComplexDataTypeDef){
                    ComplexDataTypeDef complexUdt = (ComplexDataTypeDef)udt;
                    return getMultiUdtAssosPropDBMapping(complexUdt, element);
                }
            }
            //todo 后续关联的也加上
            break;
        }
        return new HashMap<String, String>();
    }

    public HashMap<String, String> getMultiUdtAssosPropDBMapping(ComplexDataTypeDef complexUdt, IGspCommonField item){
        HashMap<String, String> map = new HashMap<String, String>();
        if(complexUdt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn)
            return map;
        for(IGspCommonField field : complexUdt.getContainElements()){
            map.put(field.getLabelID(), item.getLabelID() + "_" + field.getLabelID());
        }
        return map;
    }

    @Override
    public Object readProperty(String propertyName, ICefReader reader) {
        for (var element : bizEntityObject.getContainElements()) {
            if (!element.getLabelID().equals(propertyName))
                continue;
            if (element.getIsUdt()){
                return ReadUtils.getUdtData(false, reader, (IGspCommonElement) element);
            }
            return ReadUtils.getValue((IGspCommonElement) element, reader);
        }
        return null;
    }

    //endregion

    //region association
    @Override
    protected void initAssociations() {

        for (IGspCommonField field : bizEntityObject.getContainElements()) {
            if (field.getHasAssociation())
                initEleAssociations(field);
        }

    }

    private void initEleAssociations(IGspCommonField element) {
        if (element.getChildAssociations() == null || element.getChildAssociations().size() < 1) {
            return;
        }
        for (GspAssociation association : element.getChildAssociations()) {
            initEleAssociation(association);
        }

    }

    private void initEleAssociation(GspAssociation association) {
        GspBusinessEntity refModel = CMEngineUtil.getMetadataContent(association.getRefModelID());
        if (refModel == null) {
            throw new CefRepositoryException(String
                    .format("节点[%s]的字段[%s]上的关联模型[%s]不存在", getTableAlias(), association.getBelongElement().getName(),
                            association.getRefModelID()));
        }

        IGspCommonField belongElement = association.getBelongElement();
        String sourceId = getSourceElementId(association);
        if (sourceId == null || "".equals(sourceId)) {
            throw new CefRepositoryException("#GSPBefError#" + "关联字段【" + belongElement.getName() + "】缺少关联关系" + "#GSPBefError#");
        }

        IRootRepository refRepository = BefRtBeanUtil.getBefRepositoryFactory().createRepository(refModel.getGeneratedConfigID());
        HashMap<String, String> refColumns = new HashMap<>();


        for (IGspCommonField refElement : association.getRefElementCollection()) {
            IGspCommonElement targetElement = refModel.findElementById(refElement.getRefElementId());
            if (targetElement == null) {
                throw new CefRepositoryException("没有获取到关联带出字段的引用字段，当前实体：" + bizEntityObject.getCode() + "，关联实体："
                        + refModel.getCode() + ",字段标签：" + refElement.getLabelID());
            }
            refColumns.put(refElement.getLabelID(), targetElement.getLabelID());
        }

        IGspCommonObject targetObject = null;
        //这个If永远走不到啊。。。
        if (StringUtils.isEmpty(association)) {
            targetObject = refModel.getMainObject();
        } else {
            targetObject = getObjectByID(refModel, association.getRefObjectID());
        }
        if (targetObject == null) {
            throw new CefRepositoryException("找不到实体节点");
        }
        IGspCommonElement sourceElement = targetObject.findElement(sourceId);

        ArrayList<com.inspur.edp.cef.repository.assembler.AssoCondition> conditionList = new ArrayList<com.inspur.edp.cef.repository.assembler.AssoCondition>();
        if(association.getAssoConditions() != null && association.getAssoConditions().size() >0){
            for(AssoCondition condition :association.getAssoConditions()){
                com.inspur.edp.cef.repository.assembler.AssoCondition condi = new com.inspur.edp.cef.repository.assembler.AssoCondition();
                condi.setLeftNodeCode(condition.getLeftNodeCode());
                condi.setLeftField(condition.getLeftField());
                condi.setOperator(condition.getOperator());
                condi.setRightNodeCode(condition.getRightNodeCode());
                condi.setRightField(condition.getRightField());
                condi.setValue(condition.getValue());
                conditionList.add(condi);
            }
        }

        ArrayList<com.inspur.edp.cef.entity.repository.AssoVariable> variables = new ArrayList<>();
        if(association.getAssoVariables() != null && association.getAssoVariables().size() >0){

            for(AssoVariable variable :association.getAssoVariables()){
                com.inspur.edp.cef.entity.repository.AssoVariable assoVariable = new com.inspur.edp.cef.entity.repository.AssoVariable();
                assoVariable.setVarCode(variable.getVarCode());
                assoVariable.setVarValue(variable.getVarValue());
                variables.add(assoVariable);
            }
        }

        com.inspur.edp.cef.repository.assembler.AssociationInfo associationInfo = new com.inspur.edp.cef.repository.assembler.AssociationInfo();
        associationInfo.setNodeCode(targetObject.getCode());
        associationInfo.setSourceColumn( belongElement.getLabelID());
        associationInfo.setTargetColumn(sourceElement.getLabelID());
        associationInfo.setRefRepository(refRepository);
        associationInfo.setRefColumns(refColumns);
        associationInfo.setConfigId(refModel.getGeneratedConfigID());
        associationInfo.setWhere(association.getWhere());
        associationInfo.setAssoConditions(conditionList);
        associationInfo.setAssoVariables(variables);
        associationInfo.setRefTableAlias(association.getRefTableAlias());
        super.getAssociationInfos().add(associationInfo);

    }

    private String getSourceElementId(GspAssociation association) {
        IGspCommonField belongElement = association.getBelongElement();
        for (GspAssociationKey associationKey : association.getKeyCollection()) {
            if (associationKey.getTargetElement().equals(belongElement.getID())) {
                return associationKey.getSourceElement();
            }
        }
        return null;
    }

    private IGspCommonObject getObjectByID(IGspCommonModel model, String objectID) {
        //TODO: getAllObjectList逻辑较复杂,再根据id查找性能稍差,大部分场景都是关联主表先临时优化
        if(model.getMainObject().getID().equals(objectID)){
            return model.getMainObject();
        }
        for (IGspCommonObject item : model.getAllObjectList()) {
            if (objectID.equals(item.getID())) {
                return item;
            }
        }
        return null;
    }

    //endregion

    @Override
    protected String getNodeCode() {
        return bizEntityObject.getCode();
    }
}
